package restaurant.gui;

import java.util.ListIterator;
import java.util.Vector;

import restaurant.core.Restaurant;
import restaurant.core.Table;
import restaurant.gui.Action.Type;


/**
 * 
 * This class implement an environment that interact with the vacuum-cleaner agent.
 * 
 * @see AbstractAgent
 * @see Agent
 * 
 *
 */
public class Environment {
	
	public Vector<Agent> agents;
	public Vector<Type> currAgentActions;
	
	public Floor floor;
	
	public Environment(int length, int width){
		this.floor = new Floor(length, width, Square.Type.CLEAN);
		
		this.currAgentActions = new Vector<Action.Type>();
	}
	
	public void initialize(MainJFrame mainjframe) {
		agents = mainjframe.agents;
	}
	
	/**
	 * 
	 *  Set the perceptions according with the agent visibility.
	 *
	 * 		If agent's visibility is MY_CELL, just the state of cell where the agent is located,
	 * 		will be add to the perception.
	 *		If agent's visibility is MY_NEIGHBOURS, the state of cell where the agent is located
	 *		and the 8 cells in its Moore neighborhood will be add to the perception.
	 *		If agent's visibility is ALL, all the cells will be add to the perception.
	 * 	
	 * 		
	 * 
	 * @return  the current perception 
	 * 
	 * @see Perception
	 */
	public Perception getPerceptions() { 
		/* create a perception with a floor of unknown state */
		Perception perception = new Perception(new Floor(floor.width, floor.length, Square.Type.UNKNOWN));
		/* then add informations according to the agent visibility */
		/* add informations about all the squares */
		for (int i = 0; i < floor.length; i++)
            for (int j = 0; j < floor.width; j++)
                perception.floor.set(i,j,floor.get(i, j));
		return perception;
	}

	/**
	 * Update the environment state according to the action performed by the agent
	 */
	public void update() {
		
		synchronized (agents) {
			ListIterator<Agent> iterator = this.agents.listIterator();
			while(iterator.hasNext()) {
				Agent agent = iterator.next();
				agent.perceives(getPerceptions());
				agent.update();
				getActionAgent(agent, agent.action());
				if(agent.action() == Type.NOOP)
					floor.set(agent.x, agent.y, agent.type);
				if(agent.action() == Type.EAST || agent.action() == Type.WEST || agent.action() == Type.NORTH || agent.action() == Type.SOUTH) {
					if(agent.x == 0 && agent.y == 0)
						floor.set(agent.x, agent.y, Square.Type.DOOR);
					else if(wasTable(agent))
						floor.set(agent.x, agent.y, Square.Type.TABLE_EMPTY);
					else
						floor.set(agent.x, agent.y, Square.Type.CLEAN);
				}
				if(agent.action() == Type.NORTH && agent.x - 1 >= 0)
					agent.x--;
				if(agent.action() == Type.SOUTH && agent.x + 1 < floor.length)
					agent.x++;
				if(agent.action() == Type.EAST && agent.y + 1 < floor.width)
					agent.y++;
				if(agent.action() == Type.WEST && agent.y - 1 >= 0)
					agent.y--;
			}
		}
	}

	private boolean wasTable(Agent agent) {
		for (Table table : Restaurant.getInstance().tables.values()) {
			if(table.getCoordinate().x == agent.x && table.getCoordinate().y == agent.y)
				return true;
		}
		return false;
	}
	
	private void getActionAgent(Agent agent, Type action) {
		for(int i = 0; i < agents.size(); i++) {
			if(agents.get(i).equals(agent))
				this.currAgentActions.insertElementAt(action, i);
		}
	}
	
	public String toString(){
//		StringBuffer sb = new StringBuffer();
//		for(int i = 0; i < floor.length; i++) {
//			for(int j = 0; j < floor.width; j++) {
//				if(floor.get(i, j) == Square.Type.CUSTOMER)
//						sb.append("CCCCC ");
//				else if(floor.get(i, j) == Square.Type.DOOR)
//					sb.append("DDDDD ");
//				else if(floor.get(i, j) == Square.Type.TABLE_EMPTY)
//					sb.append("EEEEE ");
//				else if(floor.get(i, j) == Square.Type.TABLE_FULL)
//					sb.append("FFFFF ");
//				else if(floor.get(i, j) == Square.Type.WAITER)
//					sb.append("WWWWW ");
//				else if(floor.get(i, j) == Square.Type.WAITER_EXPERT)
//					sb.append("XXXXX ");
//				else if(floor.get(i, j) == Square.Type.KITCHEN)
//					sb.append("KKKKK ");
//				else
//					sb.append("----- ");
//			}
//			sb.append("\n");
//		}
//		return sb.toString();
		return "";
	}
	
	public void show(){
//		System.out.println(this);
	}
}